<?php

namespace IYUU\sdk\CoolQ\Event;

use BadRequestException;
use InternalServerErrorException;
use IYUU\sdk\CoolQ\Context;
use IYUU\sdk\CoolQ\Domain\Message as DomainMessage;
use IYUU\sdk\CoolQ\Domain\MessageGroup;
use IYUU\sdk\CoolQ\Domain\MessageGroupMaster;
use IYUU\sdk\CoolQ\Domain\MessagePrivate;
use IYUU\sdk\CoolQ\Domain\MessagePrivateMaster;
use IYUU\sdk\CoolQ\Domain\User as DomainUser;
use IYUU\sdk\CoolQ\Event;
use IYUU\sdk\CoolQ\ModulesRouter;
use Logger;
use function IYUU\sdk\CoolQ\getConfig;
use function IYUU\sdk\CoolQ\getContext;

/**
 * 上报类型：post_type -> message
 * Class Message
 * @package IYUU\sdk\CoolQ\Event
 */
class Message extends Event
{
    /**
     * 消息 SEQ
     * @var int
     */
    protected $message_seq = 0;

    /**
     * 消息 ID
     * @var string
     */
    protected $message_id = '';

    /**
     * 消息类型（群消息group，私聊消息private）
     * @var string
     */
    protected $message_type = '';

    /**
     * 消息子类型（可能的值：{friend}、{group}、{group_self}、{other}）
     * - 正常消息是 normal, 匿名消息是 anonymous, 系统提示(如「管理员已禁止群内匿名聊天」)是 notice
     * @var string
     */
    protected $sub_type = '';

    /**
     * 父类的抽象方法，子类必须实现
     * @param Context $context
     * @return mixed
     * @throws BadRequestException|InternalServerErrorException
     */
    public function index(Context $context): array
    {
        // 调试日志
        if ($this->getConfig('debug')) {
            file_put_contents(runtime_path() . '/Message.log', __METHOD__ . p($this->message, false), FILE_APPEND);
        }
        /**
         * 系统：管理员消息处理器
         * - 返回值必须为数组
         */
        if ($this->isMaster(false)) {
            if ($this->isPrivate()) {
                // 管理员私聊消息
                $result = MessagePrivateMaster::respond($context, $this);
            } else {
                // 管理员群聊消息
                $result = MessageGroupMaster::respond($context, $this);
            }
            if (!empty($result)) {
                return $result;
            }
        }

        /**
         * 系统：默认消息处理器
         * - 返回值必须为数组
         * - 检查方法是否可调用(方法名如：callable_private、callable_group)
         */
        if ($this->isPrivate()) {
            // 私聊消息private
            $result = MessagePrivate::respond($context, $this);
        } else {
            // 群消息group【违禁词/黑名单/刷屏】
            $result = MessageGroup::respond($context, $this);
        }
        if (!empty($result)) {
            return $result;
        }

        /**
         * 调用模块的路由器
         * - 模块返回值：数组、字符串
         */
        if (static::checkSendEnabled()) {
            $result = ModulesRouter::dispatcher($context, $this);
            file_debug($result, __LINE__);
            if (!empty($result)) {
                if (is_array($result)) {
                    // 1. 返回数组，原样返回
                    return $result;
                } else {
                    // 2. 返回字符串
                    if ($this->isPrivate()) {
                        // 2.1 私信：快捷回复
                        return static::reply($result);
                    } else {
                        return static::replyGroup($result, false, true);
                    }
                }
            }
        }

        return [];
    }

    /**
     * 过滤器（重写父类方法）
     * @return void
     * @throws BadRequestException
     */
    protected function filterCheck()
    {
        parent::filterCheck();
        /**
         * 系统功能：消息写入数据库
         */
        DomainMessage::save($this->getContext());
        /**
         * 系统功能：监听用户 最后发言
         */
        DomainUser::listenLastSpeak($this->getContext(), $this);
    }

    /**
     * 是否群消息group
     * @return bool
     */
    public function isGroup(): bool
    {
        return ($this->message_type === 'group') && $this->group_id;
    }

    /**
     * 是否私聊消息private
     * @return bool
     */
    public function isPrivate(): bool
    {
        return $this->message_type === 'private';
    }

    /**
     * 快捷回复消息
     * @param mixed $reply 要回复的内容
     * @param bool $auto_escape 消息内容是否作为纯文本发送 (即不解析 CQ 码) , 只在 {reply} 字段是字符串时有效
     * @return array
     */
    final public static function reply($reply, bool $auto_escape = false): array
    {
        return [
            'reply' => $reply,
            'auto_escape' => $auto_escape,
        ];
    }

    /**
     * 快捷回复群聊消息
     * @param mixed $reply 要回复的内容
     * @param bool $auto_escape 消息内容是否作为纯文本发送 (即不解析 CQ 码) , 只在 {reply} 字段是字符串时有效
     * @param bool $at_sender 是否要在回复开头 at 发送者, 发送者是匿名用户时无效(默认at发送者)
     * @param bool $delete 撤回该条消息(默认不撤回)
     * @param bool $kick 把发送者踢出群组 (需要登录号权限足够) , 不拒绝此人后续加群请求, 发送者是匿名用户时无效
     * @param bool $ban 把发送者禁言 ban_duration 指定时长, 对匿名用户也有效
     * @param null $ban_duration 禁言时长(默认30分钟)
     * @return array
     */
    final public static function replyGroup($reply, bool $auto_escape = false, bool $at_sender = true, bool $delete = false, bool $kick = false, bool $ban = false, $ban_duration = null): array
    {
        $rs = [
            'reply' => $reply,
            'auto_escape' => $auto_escape,
            'at_sender' => $at_sender,
            'delete' => $delete,
            'kick' => $kick,
            'ban' => $ban,
            'ban_duration' => $ban_duration
        ];

        // 纠错：禁言时长
        if ($ban && (!$ban_duration)) {
            $rs['ban_duration'] = 60;
        }

        return $rs;
    }

    /**
     * 检测消息发送开关 2021年8月27日
     * @return bool
     */
    final public static function checkSendEnabled(): bool
    {
        $message_type = (getContext()->get('message_type') === 'private') ? 'private' : 'group';
        return (bool)getConfig('enabled.' . $message_type);
    }
}
